<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        .menu{
            display: flex;
            justify-content: center;
        }
        .el{
            width: 100px;
            height: 100px;
            margin: 10px;
            background: skyblue
        }
        .el:nth-child(2n){
            background: peru;
        }
        .context-menu{
            position: fixed;
            display: none;
            box-shadow: 0 0 26px rgba(0,0,0,0.1);
            width: 150px;
            background: #FFF;
            border: 1px solid #eee;
            line-height: 40px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>{{title}}</h1>
        <div class="menu">
            <div class="el" @contextmenu.prevent="$refs.menu.open($event,{name:'hello'})">菜单1</div>
            <div class="el" @contextmenu.prevent="$refs.menu2.open">菜单2</div>
            <div class="el" @contextmenu.prevent="$refs.menu.open($event,{name:'menu'})">菜单3</div>
        </div>
        <!-- 作用域方式 -->
        <context-menu ref="menu">
            <template v-slot:default="slotProps">
                <div>
                    <div @click.prevent="onClick($event.target.innerText,slotProps.record)">新增</div>
                    <div @click.prevent="onClick($event.target.innerText,slotProps.record)">编辑</div>
                    <div @click.prevent="onClick($event.target.innerText,slotProps.record)">删除</div>
                </div>
            </template>
        </context-menu>
        <context-menu ref="menu2">
            <div @click.prevent="onClick($event.target.innerText,{name:'context'})">新增</div>
            <div @click.prevent="onClick($event.target.innerText,{name:'context'})">编辑</div>
            <div @click.prevent="onClick($event.target.innerText,{name:'context'})">删除</div>
        </context-menu>

    </div>
    <script src="./vue.min.js"></script>
    <script>
        Vue.component("context-menu",{
            template:`<div ref="context" style="display:none" class="context-menu"><slot :record="record" ></slot></div>`,
            
            data(){
                return {
                    contextMenu:null,
                    record:null
                }
            },
            mounted(){
                this.contextMenu = this.$refs['context'];
                this.bindEvent()
            },
            beforeDestroy(){
                this.removeEvent()
            },
            methods:{
                bindEvent(){
                    // 文档点击隐藏
                    document.addEventListener('click',this.hide)
                    // 文档滚动隐藏
                    document.addEventListener('scroll',this.hide)
                    // 鼠标滚动隐藏
                    document.addEventListener('mousewheel',this.hide)
                    // 右键菜单右键点击阻止默认事件
                    this.$el.addEventListener("contextmenu",(e)=>{e.preventDefault()})
                },
                removeEvent(){
                    document.removeEventListener('click',this.hide)
                    window.removeEventListener('scroll',this.hide)
                    window.removeEventListener('mousewheel',this.hide)
                    this.$el.removeEventListener("contextmenu",(e)=>{e.preventDefault()})
                },
                open($event,data){
                    // 设置作用域值
                    if(data){
                        this.record= data;
                    }
                    // 隐藏所有context-menu
                    let contextMenuAll = document.querySelectorAll(".context-menu");
                    Array.from(contextMenuAll).forEach(item=>{
                        item.style.display = 'none';
                        item.style.opcity = 0;
                    })
                    
                    // 设置右键菜单位置
                    this.contextMenu.style.display='block'
                    this.setPosition($event.clientX,$event.clientY);
                },
                hide(){
                    this.contextMenu.style.display='none'
                },
                setPosition(clientX,clientY){
                    // 右键菜单的rect
                    let menuRect = this.$el.getBoundingClientRect()
                    let menuWidth = menuRect.width;
                    let menuHeight = menuRect.height;
                    // 窗口宽高
                    let winWidth = window.innerWidth;
                    let winHeight = window.innerHeight;
                    // 距离底部最大值
                    let maxBottom = winHeight - menuHeight -25;
                    // 距离右边最大值
                    let maxRight = winWidth - menuWidth - 25;
                    // 边界判断 ，当点击的位置比最大值还大，设置位置为最大值
                    let endTop = 0;
                    let endLeft = 0;
                    if(clientY > maxBottom ){
                        endTop = maxBottom
                    }else{
                        endTop = clientY 
                    }
                    if(clientX > maxRight){
                        endLeft = maxRight
                    }else{
                        endLeft = clientX
                    }
                    this.contextMenu.style.top = endTop +'px'
                    this.contextMenu.style.left = endLeft +'px'
                    this.contextMenu.style.opcity = 1;
                }
            }
        })
        var vm = new Vue({
            el:"#app",
            
            data(){
                return {
                    title:"右键菜单",
                    list:[
                        {
                            id:1
                        },
                        {
                            id:2
                        },
                        {
                            id:3
                        }
                    ]
                }
            },
            methods:{
                onClick(text,item){
                    console.log(text,item.name)
                }
            }
        })
    </script>
</body>
</html>